package org.kanstantin.nwscan.crawler.network;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author kanstantin
 *
 */
public class AddressRange {
    private long addrRangeStart;
    private long addrRangeEnd;

    public AddressRange(String addressWithMaskBits) {
        if (addressWithMaskBits.contains("/")) {
            String[] arr = addressWithMaskBits.split("/");
            this.addrRangeStart = stringToLong(arr[0]);

            // if address ends with 0, increment by 1
            if (this.addrRangeStart % 0x100 == 0) {
                ++this.addrRangeStart;
            }

            int maskBits = 0;
            if (arr[1].length() > 0) {
                maskBits = Integer.parseInt(arr[1]);
            }

            this.addrRangeEnd = this.addrRangeStart + (0xFFFFFFFF >>> maskBits) - 2;  //exclude .255
        }
        else {
            this.addrRangeStart = this.addrRangeEnd = stringToLong(addressWithMaskBits);
        }
    }

    public AddressRange(long rangeStart, long rangeEnd) {
        if (rangeStart > rangeEnd) {
            throw new RuntimeException("Range end address cannot be greater than start address");
        }
        addrRangeStart = rangeStart;
        addrRangeEnd = rangeEnd;

    }

    public String getFirstAddrAsString() {
        return convertToString(addrRangeStart);
    }

    public String getLastAddrAsString() {
        return convertToString(addrRangeEnd);
    }

    public long getFirstAddrAsInteger() {
        return addrRangeStart;
    }

    public long getLastAddrAsInteger() {
        return addrRangeEnd;
    }

    public static String convertToString(long addr) {
        String res = "";
        for (int x = 0; x < 4; x++ ) {
            if (res.length() > 0) {
                res = res.concat(".");
            }
            res = res.concat("" + ((addr >>> (3 - x) * 8) & 0x000000FF));
        }
        return res;
    }

    private long stringToLong(String sourceAddr) {
            InetAddress address;
            try {
                address = InetAddress.getByName(sourceAddr);
            }
            catch (UnknownHostException ex) {
                throw new RuntimeException(ex);
            }


            byte[] tmp = address.getAddress();
            long iAddr = 0;
            for (int i = 0; i< 4; i++) {

                //   FF              FF         FF         FF
                // 1111 1111  1111 1111  1111 1111  1111 1111

                iAddr = iAddr + (byteToInt(tmp[i]) << 8 * (3 - i));
            }

        return iAddr;
    }

    private long byteToInt(byte src) {
        return 0x000000FF & (long)src;
    }
}
